package br.unisinos.arquivos;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.security.MessageDigest;
import java.util.ArrayList;

public class FileShared {
	public static final int KEY = 1950270784;
	private Path file;
	private FileAttributeRetriever fileAttr;
	private long id;

	// InputStream is = null;

	public FileShared(Path file) {
		this.file = file;
		this.id = -1;

		try {
			fileAttr = new FileAttributeRetriever(file);
			
		} catch (IOException ioex) {
			ioex.printStackTrace();
			fileAttr = null;
		}
	}

	public Path getFile() {
		return file;
	}

	public long getId() {
		if (id == -1) {
			long key = KEY;//fileAttr.getFileKey();
			System.out.println("key:" + key);

			try {

				BufferedInputStream in = new BufferedInputStream(new FileInputStream(file.toAbsolutePath().toString()));
				MessageDigest digest = MessageDigest.getInstance("MD5");

				byte[] buf = new byte[1024];
				int length = 0;

				while ((length = in.read(buf)) > 0)
					digest.update(buf, 0, length);

				byte[] md5sum = digest.digest();
				BigInteger sign = new BigInteger(1, md5sum);

				System.out.println(sign.toString());
				BigInteger op1 = sign.divide(BigInteger.valueOf(key));
				BigInteger op2 = op1.mod(BigInteger.valueOf(key));
				id = op2.intValue();
				System.out.println("ID: "+id);

			} catch (Exception e) {
				e.printStackTrace();
			}

		}

		return id;
	}

	public String getName() {
		return file.getFileName().toString();
	}

	public long getSize() {
		return fileAttr.getFileSize();
	}

	public long getTimestamp() {

		return fileAttr.getLastModifiedTime();
	}

	public ArrayList<String> getOwners() {
		ArrayList<String> owners = new ArrayList<String>();

		owners.add(fileAttr.getOwner());
		owners.add(fileAttr.getGroup());

		return owners;
	}

	/*
	 * Returns the file's data in the specified range
	 */
	public byte[] getData(long offset, long len) {
		byte[] data;
		ByteBuffer dst = ByteBuffer.allocateDirect((int) len);

		try {
			SeekableByteChannel channel0 = Files.newByteChannel(file, StandardOpenOption.READ) ;
			SeekableByteChannel channel1 = channel0;//file.newByteChannel(StandardOpenOption.READ);

			channel1.position(offset);
			channel1.read(dst);
			dst.flip();
			data = new byte[dst.limit()];
			dst.get(data);

			channel1.close();
		} catch (IOException ioex) {
			ioex.printStackTrace();
			data = null;
		}

		return data;
	}

	public ByteBuffer getData2(long offset, long len) {
		ByteBuffer dst = ByteBuffer.allocateDirect((int) len);

		try {
			SeekableByteChannel channel0 = Files.newByteChannel(file, StandardOpenOption.READ) ;
			SeekableByteChannel channel1 = channel0;//SeekableByteChannel channel1 = file.newByteChannel(StandardOpenOption.READ);

			channel1.position(offset);
			channel1.read(dst);
			dst.flip();

			channel1.close();
		} catch (IOException ioex) {
			ioex.printStackTrace();
			dst = null;
		}

		return dst;
	}

	/*
	 * public byte[] getData(long offset, long len) { byte[] data = new
	 * byte[(int)len];
	 * 
	 * try { if (is == null) is = file.newInputStream(StandardOpenOption.READ);
	 * 
	 * //long skippedBytes = is.skip(offset); //if (skippedBytes < offset) //
	 * return null;
	 * 
	 * is.read(data, 0, (int)len);
	 * 
	 * }
	 * 
	 * catch (IOException ioex) { ioex.printStackTrace(); is = null; data =
	 * null; }
	 *//*
		 * finally { if (is != null) { try { is.close(); } catch (IOException
		 * ioex) { ioex.printStackTrace(); } } }
		 */
	// return data;
	// }
}
